package notesDetection.Utilities;

import notesDetection.SFT.Complex;

public class SampleFunctionCoefficient {

	public static Complex SampleCoeffValue(double[] functionValues, int coeff, int cycleLength, int start, int stop) {
		
		final int SAMPLE_COUNT = 800;

		double realSum = 0;
		double imagSum = 0;
		
		//	An = Expectation{x[n]e^(-j*2pi*n/N)}
		for(int iteration = 0; iteration < SAMPLE_COUNT; iteration++)
		{
			//int n = GeneralNoteDetection.GetRandomInt(0, functionValues.length - 1);
			int n = GeneralNoteDetection.GetRandomInt(start, stop);
			double sineValue = Math.sin(2 * Math.PI * n * coeff / cycleLength);
			double cosineValue = Math.cos(2 * Math.PI * n * coeff / cycleLength);
			
			realSum += functionValues[n] * cosineValue;
			imagSum += functionValues[n] * sineValue;
			
		}
		//	Multiplication by 2: See BLUE comment in next function!
		return new Complex(2 * realSum / SAMPLE_COUNT, 2 * imagSum / SAMPLE_COUNT);
	}
	
	public static Complex SampleCoeffValueFull(double[] functionValues, int coeff, int cycleLength, int start, int stop) {
		
		final int SAMPLE_COUNT = stop - start + 1;

		double realSum = 0;
		double imagSum = 0;
		
		int n = start;
		//	An = Expectation{x[n]e^(-j*2pi*n/N)}
		for(int iteration = 0; iteration < SAMPLE_COUNT; iteration++)
		{
			//int n = GeneralNoteDetection.GetRandomInt(0, functionValues.length - 1);

			double sineValue = Math.sin(2 * Math.PI * (n - start) * coeff / cycleLength);
			double cosineValue = Math.cos(2 * Math.PI * (n - start) * coeff / cycleLength);
			
			realSum += functionValues[n] * cosineValue;
			imagSum += functionValues[n] * sineValue;
			
			n++;
		}
		
		/***	All but DC coefficient (coeff 0) must me multiplied by 2, because:
		 * 
		 * Expectation{A*cos[2pi*n/N]e^(-j*2pi*n/N)} ~ E{A*cos^2[2pi*n/N] + 2Ajsin[4pi*n/N]}
		 * ~ E{0.5A + 0.5A*cos[4pi*n/N]} ~ 0.5A
		 * 
		 * This is just an example. The real reason is that A[n] = A[-n]*, so we must sum 2 coeffs to get the sine amplitude.
		 * 
		 */
		
		return new Complex(2*realSum / SAMPLE_COUNT, 2*imagSum / SAMPLE_COUNT);
	}
	
	/**
	 * Same as above for complex functions
	 * (Generalization of the coeff sampling. Or previous function is a private case of this one. Whatever)
	 * 
	 * @param functionValues
	 * @param coeff
	 * @param cycleLength
	 * @param N
	 * @return
	 */
	public static Complex SampleCoeffValue(Complex[] functionValues, int coeff, int cycleLength, int N) {
		
		final int SAMPLE_COUNT = 800;

		double realSum = 0;
		double imagSum = 0;
		
		//	An = Expectation{x[n]e^(-j*2pi*n/N)}
		for(int iteration = 0; iteration < SAMPLE_COUNT; iteration++)
		{
			int n = GeneralNoteDetection.GetRandomInt(0, N - 1);
			double sineValue = Math.sin(2 * Math.PI * n * coeff / cycleLength);
			double cosineValue = Math.cos(2 * Math.PI * n * coeff / cycleLength);
			
			realSum += functionValues[n].Re() * cosineValue - functionValues[n].Im() * sineValue;
			imagSum += functionValues[n].Im() * cosineValue + functionValues[n].Re() * sineValue;
			
		}
		return new Complex(2 * realSum / SAMPLE_COUNT, 2 * imagSum / SAMPLE_COUNT);
	}
	
}
